<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { Vector2 } from 'three'


const container = ref(null)
let scene, camera, renderer, cube, sphere;
let animationId = null;
let controls = null;
const group = new THREE.Group();
// 交互事件
const raycaster = new THREE.Raycaster()
const mouse = new Vector2()
let direction = 1 // 1=顺时针，-1=逆时针

// 初始化场景
function initScene() {
  // 场景
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x87CEEB)

  // 相机（透视相机）
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  )
  camera.position.z = 5

  // 渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  window.addEventListener('resize', onWindowResize);
}

// 创建几何体
function createObjects() {
    group.clear() // 复用已声明的组容器
  // 绿色立方体
  const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
  const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
  group.add(cube);

  // 蓝色球体
  const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);
  const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff, needsUpdate: true });
  sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
  sphere.position.x = 2;
  group.add(sphere);

  // 计算包围盒中心
  const box3 = new THREE.Box3().expandByObject(group);
  const center = new THREE.Vector3();
  box3.getCenter(center);
  
  // 调整组位置使场景居中 
  group.position.sub(center);
  scene.add(group);
}


// 交互
// 点击事件处理函数
const handleClick = (event)=> {
  // 转换鼠标坐标为归一化设备坐标
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
  
  // 更新射线检测器
  raycaster.setFromCamera(mouse, camera)
  
  // 检测相交对象
  const intersects = raycaster.intersectObjects(group.children, true)
  if (intersects.length > 0) {
    const clickedObj = intersects[0].object
    if (clickedObj === sphere) {
      // 点击球体：随机改变颜色
      sphere.material.color.setHex(Math.random() * 0x87CEEB)
    } else if (clickedObj === cube) {
      // 点击立方体：改变运动方向
      direction *= -1 // 反转方向
    }
  }
}

const debouncedHandleClick = debounce(handleClick, 100);

// 高阶防抖函数（支持立即执行）
function debounce(func, wait, immediate = false) {
  let timeout;
  return function (...args) {
    const context = this;
    const later = () => {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };

    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
}

// 动画循环
function animate() {
    sphere.position.x = 2 * Math.cos(Date.now() * 0.001 * direction)
    sphere.position.z = 2 * Math.sin(Date.now() * 0.001 * direction)
  renderer.render(scene, camera)
  animationId = requestAnimationFrame(animate)
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

onMounted(() => {
  initScene()
  createObjects()
  container.value.appendChild(renderer.domElement)
  // 初始化轨道控制器 
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true; // 启用阻尼效果
  controls.dampingFactor = 0.05;
  animate()
  // 交互
  renderer.domElement.addEventListener('click', debouncedHandleClick)
})

onUnmounted(() => {
    controls.dispose(); // 销毁控制器 
  cancelAnimationFrame(animationId)
  window.removeEventListener('resize', onWindowResize);
  renderer.domElement.removeEventListener('click', debouncedHandleClick)
  scene.remove(group)
  group.traverse(obj => {
    if (obj.material) obj.material.dispose()
    if (obj.geometry) obj.geometry.dispose()
  })
  renderer.dispose()
})
</script>

<template>
  <div ref="container" class="canvas-container"></div>
</template>

<style>
body {
  margin: 0;
  overflow: hidden;
}
.canvas-container canvas {
    width: 100%;
    left: 0;
  display: block;
}
</style>